package br.com.controller;


import br.com.controller.util.JsfUtil;
import java.text.ParseException;
import java.util.List;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.persistence.Transient;
import br.com.model.dao.AbstractDao;

/**
 * @author Lindoélio Lázaro
 */

public abstract class AbstractMB<E> {


    protected static String ALTERAR = "alterar";
    protected static String INCLUIR = "incluir";
    protected static String EXCLUIR = "excluir";
    protected static String LISTAR = "listar";
    private E entidade;
    private List<E> entidades;
    
    @Transient
    protected DataModel dataModel;
    
    @Transient
    protected AbstractDao<E> dao;
    protected String operacao;
    protected String mensagemSucesso;
    protected String mensagemFalha;

    public DataModel getListagem() throws ParseException {
        this.setEntidades(this.dao.list());
        this.dataModel = new ListDataModel(this.getEntidades());
        return this.dataModel;
    }

    public String prepararListagem() {
        this.operacao = LISTAR;
        return "list";
    }

    public String prepararInclusao() {
        this.operacao = INCLUIR;
        return "form";
    }

    public String prepararAlteracao() {
        try {
            this.setEntidade((E) this.getSelecao());
            if (this.getEntidade() == null) {
                if (this.mensagemFalha == null) {
                    this.mensagemFalha = "Falha ao selecionar o registro para alteração!";
                }
                JsfUtil.addErrorMessage(this.mensagemFalha);
                this.operacao = LISTAR;
            } else {
                this.operacao = ALTERAR;
            }
        } finally {
            this.mensagemFalha = null;
            if (this.operacao.equals(LISTAR)) {
                return "list";
            } else {
                return "form";
            }
        }
    }

    public void prepararExclusao() {
        try {
            this.setEntidade((E) this.getSelecao());
            if (this.getEntidade() == null) {
                JsfUtil.addErrorMessage("Falha ao selecionar o registro para exclusão!");
            } else {
                this.operacao = EXCLUIR;
            }
        } finally {
            this.mensagemFalha = null;
        }
    }

    protected String incluir() {
        try {
            this.dao.insert((E) this.getEntidade());
            if (this.mensagemSucesso == null) {
                this.mensagemSucesso = "Registro adicionado com sucesso!";
            }
            JsfUtil.addSuccessMessage(this.mensagemSucesso);
            this.operacao = null;
        } catch (Exception e) {
            if (this.mensagemFalha == null) {
                this.mensagemFalha = "Falha na inclusão!";
            }
            JsfUtil.ensureAddErrorMessage(e, this.mensagemFalha);
        } finally {
            this.mensagemSucesso = null;
            this.mensagemFalha = null;
            if (this.operacao == null) {
                return "list";
            } else {
                return "form";
            }
        }
    }

    protected String atualizar() {
        return this.atualizar(false, null);
    }

    protected String atualizar(boolean withoutChildrens, Integer id) {
        try {
            if (withoutChildrens) {
                this.dao.update((E) this.getEntidade(), id);
            } else {
                this.dao.update((E) this.getEntidade());
            }
            if (this.mensagemSucesso == null) {
                this.mensagemSucesso = "Registro alterado com sucesso.";
            }
            JsfUtil.addSuccessMessage(this.mensagemSucesso);
            this.operacao = null;
        } catch (Exception e) {
            if (this.mensagemFalha == null) {
                this.mensagemFalha = "Falha na alteração.";
            }
            JsfUtil.ensureAddErrorMessage(e, this.mensagemFalha);
        } finally {
            this.mensagemSucesso = null;
            this.mensagemFalha = null;
            if (this.operacao == null) {
                return "list";
            } else {
                return "form";
            }
        }
    }

    protected String desativar(Integer id) {
        try {
            this.mensagemSucesso = "Registro excluído com sucesso.";
            this.mensagemFalha = "Falha na exclusão.";
            this.atualizar(true, id);
        } finally {
            return "list";
        }
    }

    protected String deletar(Object id) {
        try {
            this.dao.delete(id);
            if (this.mensagemSucesso == null) {
                this.mensagemSucesso = "Registro excluído com sucesso!";
            }
            JsfUtil.addSuccessMessage(this.mensagemSucesso);
        } catch (Exception e) {
            if (this.mensagemFalha == null) {
                this.mensagemFalha = "Falha na exclusão permanente!";
            }
            JsfUtil.ensureAddErrorMessage(e, this.mensagemFalha);
        } finally {
            this.mensagemSucesso = null;
            this.mensagemFalha = null;
            return "list";
        }
    }

    public String confirmar() {
        if (this.isInclusao()) {
            return this.incluir();
        } else if (this.isAlteracao()) {
            return this.atualizar();
        } else {
            return null;
        }
    }

    protected E getSelecao() {
        return ((E) this.dataModel.getRowData());
    }

    public E getEntidade() {
        return entidade;
    }

    protected void setEntidade(E entidade) {
        this.entidade = entidade;
    }

    public List<E> getEntidades() {
        return entidades;
    }

    protected void setEntidades(List<E> entidades) {
        this.entidades = entidades;
    }

    public boolean isInclusao() {
        if (this.operacao.equals(INCLUIR)) {
            return true;
        } else {
            return false;
        }
    }

    public boolean isAlteracao() {
        if (this.operacao.equals(ALTERAR)) {
            return true;
        } else {
            return false;
        }
    }

    public boolean isExclusao() {
        if (this.operacao.equals(EXCLUIR)) {
            return true;
        } else {
            return false;
        }
    }
}
